"""工具相关路由"""

from fastapi import APIRouter, HTTPException, Depends, BackgroundTasks
from pydantic import BaseModel
from typing import Dict, Any, List, Optional, Union
import logging
import asyncio
import time

from backend.common.config import config_manager
from backend.tools.tool_registry import tool_registry
from backend.tools.tool_caller import ToolCaller
from backend.logger_setup import get_logger_with_trace_id
from backend.middleware.trace_middleware import get_trace_id
from backend.common.status_manager import status_manager

# 创建路由器
router = APIRouter(
    prefix=f"/{config_manager.api.version}/tools",
    tags=["工具"],
    responses={404: {"description": "未找到"}},
)

logger = logging.getLogger('api.tools')

# 定义请求模型
class ToolCallRequest(BaseModel):
    tool_name: str
    parameters: Dict[str, Any]
    timeout: Optional[int] = 30
    async_exec: bool = False

class WebSearchRequest(BaseModel):
    query: str
    num_results: Optional[int] = 5
    search_type: str = "web"

class FunctionCallRequest(BaseModel):
    function_name: str
    arguments: Dict[str, Any]


@router.post("/call", operation_id="tools_call")
async def call_tool(
    request: ToolCallRequest,
    background_tasks: BackgroundTasks = BackgroundTasks(),
    trace_id: str = Depends(get_trace_id)
):
    """通用工具调用接口"""
    # 获取带trace_id的logger
    log = get_logger_with_trace_id(logger, trace_id)
    log.info(f"接收到工具调用请求: tool_name={request.tool_name}, async_exec={request.async_exec}")
    
    try:
        # 检查工具是否存在且已注册
        if not tool_registry.is_tool_registered(request.tool_name):
            raise HTTPException(
                status_code=404,
                detail=f"工具 '{request.tool_name}' 未注册"
            )
        
        # 检查工具是否在白名单中
        if not tool_registry.is_tool_whitelisted(request.tool_name):
            raise HTTPException(
                status_code=403,
                detail=f"工具 '{request.tool_name}' 不在白名单中，无法调用"
            )
        
        # 获取工具信息
        tool_info = tool_registry.get_tool_info(request.tool_name)
        
        # 准备调用参数
        tool_params = {
            "tool_name": request.tool_name,
            "parameters": request.parameters,
            "timeout": request.timeout,
            "trace_id": trace_id
        }
        
        if request.async_exec:
            # 异步执行
            task_id = f"tool_{trace_id[:8]}_{int(time.time())}"
            
            # 记录任务状态
            status_manager.add_tool_status(task_id, {
                "status": "pending",
                "tool_name": request.tool_name,
                "parameters": request.parameters,
                "trace_id": trace_id,
                "created_at": time.time()
            })
            
            # 添加后台任务
            background_tasks.add_task(
                execute_tool_async,
                task_id, tool_params
            )
            
            return {
                "task_id": task_id,
                "status": "pending",
                "message": f"工具 '{request.tool_name}' 调用已提交，正在后台执行",
                "status_url": f"/{config_manager.api.version}/tools/status/{task_id}",
                "trace_id": trace_id
            }
        else:
            # 同步执行
            start_time = time.time()
            
            # 获取工具调用器
            tool_caller = ToolCaller()
            
            # 执行工具
            result = await tool_caller.call_tool(**tool_params)
            
            # 计算耗时
            execution_time = time.time() - start_time
            
            # 记录指标
            log.info(f"工具 '{request.tool_name}' 调用完成: 耗时={execution_time:.2f}s")
            
            return {
                "tool_name": request.tool_name,
                "result": result,
                "execution_time": execution_time,
                "trace_id": trace_id
            }
    except HTTPException:
        # 重新抛出HTTP异常
        raise
    except Exception as e:
        log.error(f"工具调用失败: {str(e)}")
        raise HTTPException(status_code=500, detail=f"Tool call failed: {str(e)}")


@router.post("/web-search", operation_id="tools_web_search")
async def web_search(
    request: WebSearchRequest,
    trace_id: str = Depends(get_trace_id)
):
    """Web搜索工具接口"""
    # 获取带trace_id的logger
    log = get_logger_with_trace_id(logger, trace_id)
    log.info(f"接收到Web搜索请求: query={request.query[:50]}..., num_results={request.num_results}")
    
    try:
        # 验证工具是否可用
        if not tool_registry.is_tool_available("web_search"):
            raise HTTPException(
                status_code=503,
                detail="Web搜索工具当前不可用"
            )
        
        # 准备参数
        search_params = {
            "query": request.query,
            "num_results": request.num_results,
            "search_type": request.search_type
        }
        
        # 获取工具调用器
        tool_caller = ToolCaller()
        
        # 执行搜索
        results = await tool_caller.call_tool(
            tool_name="web_search",
            parameters=search_params,
            trace_id=trace_id
        )
        
        return {
            "query": request.query,
            "results": results,
            "num_results": len(results) if isinstance(results, list) else 0,
            "trace_id": trace_id
        }
    except HTTPException:
        # 重新抛出HTTP异常
        raise
    except Exception as e:
        log.error(f"Web搜索失败: {str(e)}")
        raise HTTPException(status_code=500, detail=f"Web search failed: {str(e)}")


@router.get("/list", operation_id="tools_list")
async def list_tools(
    show_details: bool = False,
    trace_id: str = Depends(get_trace_id)
):
    """列出所有已注册的工具"""
    # 获取带trace_id的logger
    log = get_logger_with_trace_id(logger, trace_id)
    log.info(f"列出工具: show_details={show_details}")
    
    try:
        # 获取工具列表
        tools = tool_registry.get_registered_tools(show_details)
        
        # 分类工具
        result = {
            "total": len(tools),
            "trace_id": trace_id
        }
        
        if show_details:
            # 详细信息
            result["tools"] = tools
        else:
            # 仅工具名称和状态
            result["tools"] = [{
                "name": tool["name"],
                "description": tool["description"],
                "available": tool["available"],
                "whitelisted": tool["whitelisted"]
            } for tool in tools]
        
        return result
    except Exception as e:
        log.error(f"列出工具失败: {str(e)}")
        raise HTTPException(status_code=500, detail=f"Failed to list tools: {str(e)}")


@router.get("/status/{task_id}", operation_id="tools_status")
async def get_tool_status(
    task_id: str,
    trace_id: str = Depends(get_trace_id)
):
    """获取异步工具调用的状态"""
    # 获取带trace_id的logger
    log = get_logger_with_trace_id(logger, trace_id)
    log.info(f"获取工具任务状态: task_id={task_id}")
    
    try:
        # 从状态管理器获取状态
        status = status_manager.get_tool_status(task_id)
        
        if not status:
            raise HTTPException(status_code=404, detail=f"Task {task_id} not found")
        
        # 添加trace_id到返回结果
        status["trace_id"] = trace_id
        
        return status
    except HTTPException:
        # 重新抛出HTTP异常
        raise
    except Exception as e:
        log.error(f"获取工具状态失败: {str(e)}")
        raise HTTPException(status_code=500, detail=f"Failed to get tool status: {str(e)}")


@router.post("/function-call", operation_id="tools_function_call")
async def function_call(
    request: FunctionCallRequest,
    trace_id: str = Depends(get_trace_id)
):
    """函数调用接口，用于动态调用后端函数"""
    # 获取带trace_id的logger
    log = get_logger_with_trace_id(logger, trace_id)
    log.info(f"接收到函数调用请求: function_name={request.function_name}")
    
    try:
        # 检查函数是否存在且已注册
        if not tool_registry.is_function_registered(request.function_name):
            raise HTTPException(
                status_code=404,
                detail=f"函数 '{request.function_name}' 未注册"
            )
        
        # 获取函数
        function_info = tool_registry.get_function_info(request.function_name)
        
        # 执行函数
        start_time = time.time()
        
        # 注意：这里需要确保函数是可安全调用的，避免安全风险
        result = function_info["function"](**request.arguments)
        
        # 计算耗时
        execution_time = time.time() - start_time
        
        # 记录指标
        log.info(f"函数 '{request.function_name}' 调用完成: 耗时={execution_time:.2f}s")
        
        return {
            "function_name": request.function_name,
            "result": result,
            "execution_time": execution_time,
            "trace_id": trace_id
        }
    except HTTPException:
        # 重新抛出HTTP异常
        raise
    except Exception as e:
        log.error(f"函数调用失败: {str(e)}")
        raise HTTPException(status_code=500, detail=f"Function call failed: {str(e)}")


async def execute_tool_async(task_id: str, tool_params: Dict[str, Any]):
    """异步执行工具调用"""
    log = logging.getLogger('tools.async_executor')
    tool_name = tool_params["tool_name"]
    
    try:
        # 更新状态为执行中
        status_manager.update_tool_status(task_id, {
            "status": "running",
            "start_time": time.time()
        })
        
        # 获取工具调用器
        tool_caller = ToolCaller()
        
        # 执行工具
        result = await tool_caller.call_tool(**tool_params)
        
        # 计算耗时
        execution_time = time.time() - status_manager.get_tool_status(task_id).get("start_time", time.time())
        
        # 更新状态为完成
        status_manager.update_tool_status(task_id, {
            "status": "completed",
            "result": result,
            "execution_time": execution_time,
            "end_time": time.time()
        })
        
        log.info(f"异步工具 '{tool_name}' 调用完成: task_id={task_id}, 耗时={execution_time:.2f}s")
    except Exception as e:
        error_message = str(e)
        log.error(f"异步工具 '{tool_name}' 调用失败: task_id={task_id}, error={error_message}")
        
        # 更新状态为失败
        status_manager.update_tool_status(task_id, {
            "status": "failed",
            "error": error_message,
            "end_time": time.time()
        })